package org.file5.service.impl;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;

import net.sf.jmimemagic.Magic;
import net.sf.jmimemagic.MagicMatch;

import org.apache.log4j.Logger;
import org.file5.exception.ImageTooLargeException;
import org.file5.exception.InvalidSwagImageException;
import org.file5.exception.LoadImageFromURLException;
import org.file5.service.ImageService;
import org.springframework.stereotype.Service;

import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;

/**
 * Image Service
 * 
 * @author scott
 * 
 */
@Service("imageService")
public class ImageServiceImpl implements ImageService {

	private static final Logger log = Logger.getLogger(ImageServiceImpl.class);
	public static final String PATH_TO_DEFAULT_IMAGE = "images/no_photo.jpg";

	private static byte[] defaultImage;
	private static byte[] defaultThumbnailImage;

	// app
	// for checking mime type
	private Magic jmimeMagicParser = new Magic();


	public byte[] getResizedThumbnailImageBytes(int width,int height,byte[] originalImageBytes) {
		if (defaultThumbnailImage == null || defaultThumbnailImage.length != 0) {
			defaultThumbnailImage = resizeImage(originalImageBytes, width,
					height);
		}
		return defaultThumbnailImage;


	}

	private byte[] resizeImage(byte[] imageBytes, int resizedWidth,
			int resizedHeight) {

		ImagesService imagesService = ImagesServiceFactory.getImagesService();
		Image oldImage = ImagesServiceFactory.makeImage(imageBytes);
		Transform resize = ImagesServiceFactory.makeResize(resizedWidth,
				resizedHeight);
		Image newImage = imagesService.applyTransform(resize, oldImage,
				ImagesService.OutputEncoding.valueOf("JPEG"));
		return newImage.getImageData();
	}



	/**
	 * This is the only way I can get the base URL to this app
	 * 
	 * @param req
	 * @return
	 */
	private String constructDefaultImageURL(String requestURL) {
		String baseURL = requestURL.substring(0, requestURL
				.lastIndexOf("/springmvc"));
		return baseURL + "/" + PATH_TO_DEFAULT_IMAGE;
	}

	/**
	 * Lazy load default image for use if SwagItem isn't created with an image
	 * ImageIO had a nice way to do it but it is blacklisted on appengine :(
	 * 
	 * @param requestURL
	 *            to construct the full image URL
	 */
	public byte[] getDefaultImageBytes(String requestURL) {
		if (defaultThumbnailImage == null || defaultThumbnailImage.length != 0) {
			String defaultImageURLString = constructDefaultImageURL(requestURL);
			ByteArrayOutputStream bas = null;
	
			// create defaultImage byte[] from URL
			// ouch this would have been easier with ImageIO!
			try {
				URL defaultImageURL = new URL(defaultImageURLString);
				BufferedInputStream bis = new BufferedInputStream(defaultImageURL
						.openStream());
				ByteArrayOutputStream baos = new ByteArrayOutputStream();
				int i;
				while ((i = bis.read()) != -1) {
					baos.write(i);
				}
				defaultImage = baos.toByteArray();
				return defaultImage;
			} catch (IOException e) {
				log.error("couldn't load defaultImage at " + defaultImageURLString,
						e);
				return null;
			} finally {
				try {
					if (bas != null)
						bas.close();
				} catch (IOException e) {
					// ignore
				}
			}
		}
		return defaultImage;
	}

	

	/**
	 * 
	 * public so that it can be used by AdminService
	 * 
	 * @return image data from swagItem
	 */
	public byte[] getImageDataFromURL(String imageURL)
			throws LoadImageFromURLException, ImageTooLargeException {
		BufferedInputStream bis = null;
		ByteArrayOutputStream bos = null;
		try {
			// fetch URL as InputStream
			URL url = new URL(imageURL);
			bis = new BufferedInputStream(url.openStream());
			// write it to a byte[] using a buffer since we don't know the exact
			// image size
			byte[] buffer = new byte[1024];
			bos = new ByteArrayOutputStream();
			int i = 0;
			while (-1 != (i = bis.read(buffer))) {
				bos.write(buffer, 0, i);
			}
			byte[] imageData = bos.toByteArray();
			if (imageData.length > 150000) {
				throw new ImageTooLargeException(url.toString(), 150000);
			}
			return imageData;
		} catch (IOException e) {
			throw new LoadImageFromURLException(imageURL, e);
		} finally {
			try {
				if (bis != null)
					bis.close();
				if (bos != null)
					bos.close();
			} catch (IOException e) {
				// ignore
			}
		}
	}

	/**
	 * 
	 * Make sure they're uploading a picture
	 * 
	 * @param imageData
	 * @throws InvalidSwagImageException
	 */
	public void checkImageMimeType(byte[] imageData)
			throws InvalidSwagImageException {
		String mimeType;
		try {
			MagicMatch match = jmimeMagicParser.getMagicMatch(imageData);
			mimeType = match.getMimeType();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			log.error(e);
			throw new InvalidSwagImageException(e);
		}
		if (!(     ("image/gif".equals(mimeType))
				|| ("image/png".equals(mimeType)) 
				|| ("image/jpeg".equals(mimeType))
			)) {
			throw new InvalidSwagImageException(mimeType);
		}
	}

	@Override
	public byte[] getResizedImageBytes(int width,int height,byte[] originalImageBytes) {
		return resizeImage(originalImageBytes, width, height);
	}




}